package com.springboot.demo.core.utils;

import com.springboot.demo.core.constant.CodeMsg;
import com.springboot.demo.core.exception.CosyException;
import com.springboot.demo.module.entity.TSysUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

/**
 * redis 各类存取工具类
 *
 * @author Francis
 * @version 1.0
 * @date 2019-07-05 14:11
 */
@Component
public class RedisUtils {

    private static RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RedisTemplate<String, Object> oriRedisTemplate;


    @PostConstruct
    public void beforeInit(){
        redisTemplate = oriRedisTemplate;
    }


    /***********************************************************************************************************
     * ****************************************存储 -- 不设置失效时间*******************************************
     ***********************************************************************************************************/
    /**
     * 字符串键值对 -- 存储-不设置失效时间
     * @param key key
     * @param value value
     */
    public static void save(String key, String value){
        validateKeyAndValue(key, value);
        
        redisTemplate.opsForValue().set(key, value);
    }


    /**
     * 对象 -- 存储-不设置失效时间
     * @param key key
     * @param t 实体对象
     */
    public static <T> void save(String key, T t){
        validateKeyAndValue(key, t);

        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.opsForValue().set(key, t);
    }


    /**
     * json -- 存储-不设置失效时间
     * @param key key
     * @param t value
     * @param clazz T.class
     */
    public static <T> void save(String key, T t, Class<T> clazz){
        validateKeyAndValue(key, t);
        validateClazz(clazz);

        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(clazz));
        redisTemplate.opsForValue().set(key, t);
    }




    /***********************************************************************************************************
     * ****************************************存储 -- 设置失效时间*******************************************
     ***********************************************************************************************************/
    /**
     * 字符串键值对 -- 存储-设置失效时间
     * @param key key
     * @param value value
     * @param timeout 失效时间
     * @param unit 失效时间单位
     */
    public static void save(String key, String value, long timeout, TimeUnit unit){
        validateKeyAndValue(key, value);
        validateTimeAndUnit(timeout, unit);

        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }


    /**
     * 对象 -- 存储-不设置失效时间
     * @param key key
     * @param t 实体对象
     * @param timeout 失效时间
     * @param unit 失效时间单位
     */
    public static <T> void save(String key, T t, long timeout, TimeUnit unit){
        validateKeyAndValue(key, t);
        validateTimeAndUnit(timeout, unit);

        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.opsForValue().set(key, t, timeout, unit);
    }


    /**
     * json -- 存储-不设置失效时间
     * @param key key
     * @param t value
     * @param clazz T.class
     * @param timeout 失效时间
     * @param unit 失效时间单位
     */
    public static <T> void save(String key, T t, Class<T> clazz, long timeout, TimeUnit unit){
        validateKeyAndValue(key, t);
        validateClazz(clazz);
        validateTimeAndUnit(timeout, unit);

        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(clazz));
        redisTemplate.opsForValue().set(key, t, timeout, unit);
    }




    /***********************************************************************************************************
     * ***********************************************  读取  **************************************************
     ***********************************************************************************************************/
    /**
     * 字符串键值对 -- 读取
     * @param key key
     */
    public static String getKey4String(String key){
        validateKey(key);

        return (String) redisTemplate.opsForValue().get(key);
    }


    /**
     * 对象 -- 读取
     * @param key key
     * @param <T> 返回对象
     * @return
     */
    public static <T> T getKey4Pojo(String key, Class<T> clazz){
        validateKey(key);
        validateClazz(clazz);

        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        return clazz.cast(redisTemplate.opsForValue().get(key));
    }


    /**
     * 对象json -- 读取
     * @param key key
     * @param clazz t.class()
     * @param <T> 返回对象
     * @return
     */
    public static <T> T getKey4Json(String key, Class<T> clazz){
        validateKey(key);
        validateClazz(clazz);

        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(clazz));
        return clazz.cast(redisTemplate.opsForValue().get(key));
    }




    /***********************************************************************************************************
     * *******************************************  辅助校验工具  **********************************************
     ***********************************************************************************************************/
    /**
     * 校验 key and value
     * @param key
     * @param value
     */
    private static void validateKeyAndValue(String key, Object value){
        if(StringUtils.isEmpty(key) || StringUtils.isEmpty(value)){
            throw new CosyException(CodeMsg.KEY_AND_VALUE_MUST_BE_NOT_EMPTY);
        }
    }

    /**
     * 校验 key
     * @param key
     */
    private static void validateKey(String key){
        if(StringUtils.isEmpty(key)){
            throw new CosyException(CodeMsg.KEY_MUST_BE_NOT_EMPTY);
        }
    }


    /**
     * 校验 timeout and unit
     * @param timeout
     * @param unit
     */
    private static void validateTimeAndUnit(long timeout, TimeUnit unit){
        if(StringUtils.isEmpty(timeout) || StringUtils.isEmpty(unit)){
            throw new CosyException(CodeMsg.TIME_AND_UNIT_MUST_BE_NOT_EMPTY);
        }
    }


    /**
     * 校验 class 类
     * @param clazz
     * @param <T>
     */
    private static <T> void validateClazz(Class<T> clazz){
        if(StringUtils.isEmpty(clazz)){
            throw new CosyException(CodeMsg.CLASS_MUST_BE_NOT_EMPTY);

        }
    }
}
